Introduction

In this project, we’re examining inspection scores for restaurants in and around Austin, Texas, from 2014 through early 2017. Scores are determined through routine inspections, usually conducted twice a year. If a score lower than 70 is recorded in a yearly inspection, the restaurant will be subjected to one or more followup visits to ensure a return to compliance. All of our restaurant inspection records include geographical information in the form of zip codes, allowing the use of additional datasets to further explore the data. Visit https://data.world/kvaughn/s-17-dv-project-6 to explore our datasets, or see below for the visualizations we’ve made of the data.

R Configuration

Below we display our sessionInfo().

The Data

The restaurant inspection dataset was provided through the City of Austin’s Open Data Portal, https://data.austintexas.gov/. This free download is available in multiple formats at https://data.austintexas.gov/Health/Restaurant-Inspection-Scores/uthw-a7ih. For this project, we downloaded a CSV file and cleaned it using the Extract-Translate-Load procedure outlined below.

Extract-Translate-Load (ETL)

The dataset we received needed some cleaning, as it was unreadable to Tableau in its original CSV formatting. We used the Extract-Translate-Load method discussed in class, and built an R script found at “../01 Data/ETLRestaurant.R” We also cleaned up the join query used in our Tableau visualizations; it can be found at “../01 Data/ETLQuery.R” If you’d like to follow along, here’s how we processed the restaurant inspection data:

Step-By-Step Instructions

First, download the uncleaned CSV: https://data.austintexas.gov/api/views/ecmv-9xxi/rows.csv?accessType=DOWNLOAD. Prepend “PreETL_” to the file name, and put it in a folder called CSVs in the same directory as this project (s17dvproject5-vaughn-cannata-martinez).

Step 1: Set up the environment

Note that we have one column of numeric data (“Score”), one column of dates (“Inspection Date”), three columns of strings (“Restaurant Name”, “Address”, and “Process Description”), and two columns of numeric data used categorically (“Zip Code” and “Facility ID”). For the sake of ease of use, these last two columns will be treated as strings.

# Set working directory
setwd("~/s17dvfinalproject-vaughn-cannata-martinez-1/00 Docs")

# Set filepath
file_path = "../../CSVs/PreETL_Restaurant_Inspection_Scores.csv"

# Create dataframe from original CSV
df <- read.csv(file_path, stringsAsFactors = FALSE)

# Standardize column names
names(df) <- gsub("\\.+", " ", names(df))

# Print column names and types
str(df)

Step 2: Collect columns by type

We’ve grouped the date column separately from measures and dimensions; while Tableau will recognize these data as dates, it seems prudent to reclassify them into a standardized format.

# Select string data as 'dimensions'
dimensions <- c("Restaurant Name", "Zip Code", "Address", "Process Description", "Facility ID")

# Select dates as 'dates'
dates <- c("Inspection Date")

# Select all remaining data as 'measures'
measures <- setdiff(names(df), union(dimensions, dates))

Step 3: Remove special characters

Here we remove special characters from all of our data. These characters can serve no purpose in the data, and might cause problems in the analysis process. To improve readability, special characters have been replaced by spaces.

# Get rid of special characters in each column.
for(n in names(df)) {
  df[n] <- data.frame(lapply(df[n], gsub, pattern="[^ -~]",replacement= " "), stringsAsFactors = FALSE)
}

Step 4: Modify records in dimensions

Now we go through all of the character-based columns (grouped as dimensions) and remove troublesome characters. Ampersands are replaced with “and”, semicolons are replaced with colons, and single- and double-quotes are removed outright. Data of NA (null) is replaced with an empty string.

# This function will replace NA data with an empty string
na2emptyString <- function (x) {
  x[is.na(x)] <- ""
  return(x)
}
# We'll apply this to all columns grouped as dimensions
if( length(dimensions) > 0) {
  for(d in dimensions) {
    # Change NA to the empty string.
    df[d] <- data.frame(lapply(df[d], na2emptyString), stringsAsFactors = FALSE)
    # Get rid of " and ' in dimensions.
    df[d] <- data.frame(lapply(df[d], gsub, pattern="[\"']",replacement= ""), stringsAsFactors = FALSE)
    # Change & to and in dimensions.
    df[d] <- data.frame(lapply(df[d], gsub, pattern="&",replacement= " and "), stringsAsFactors = FALSE)
    # Change : to ; in dimensions.
    df[d] <- data.frame(lapply(df[d], gsub, pattern=":",replacement= ";"), stringsAsFactors = FALSE)
  }
}

Step 5: Modify dates

Here we ensure that dates are formatted correctly.

if( length(dates) > 1 || ! is.na(dates)) {
  for(y in dates) {
    # Format as dates
    df[y] <- data.frame(lapply(df[y], function(y) as.Date(y, format = "%m/%d/%y")), stringsAsFactors = FALSE)
  }
}

Step 6: Modify measures

Now we take all of the non-numeric characters out of our measures.

na2zero <- function (x) {
  x[is.na(x)] <- 0
  return(x)
}
# Get rid of all characters in measures except for numbers, the - sign, and period.dimensions, and change NA to 0.
if(length(measures) > 1 || ! is.na(measures)) {
  for(m in measures) {
    df[m] <- data.frame(lapply(df[m], gsub, pattern="[^--.0-9]",replacement=""), stringsAsFactors = FALSE)
    df[m] <- data.frame(lapply(df[m], na2zero), stringsAsFactors = FALSE)
    df[m] <- data.frame(lapply(df[m], function(m) as.numeric(as.character(m)))) # This is needed to turn measures back to numeric because gsub turns them into strings.
  }
}

Step 7: Dummy check

Always a useful thing. Let’s look at our data and see what we’ve got. We’re expecting all data to be in character form except “Score”, which will be numeric, and our date column named “Inspection Date”.

# Take a look and make sure it's what you think it should be:
print(summary(df))

Step 8: Write to a new file

Our data looks good, and we need to write it to a new file.

# Now write it to a new clean file.
write.csv(df, gsub("PreETL_", "", file_path), row.names=FALSE, na = "")

Visualizations

Interesting Things

Chinatown

Generally speaking, low scores are outliers for restaurants. The inspector caught them on a bad day, perhaps. Look at the histogram for an indication of the proportion of passing scores (above 70) versus failing scores.
All Scores Histogram

If you’re interested in seeing the whole collection of scores for a restaurant with at least one low score, use our Shiny boxplot and select the zipcode of interest. Some restaurants demonstrate a trend in their low scores that goes beyond “one bad day”. Chinatown, in 78731, is a good example of this. A score of 70 or higher is considered ‘passing,’ while a score below 70 triggers an automatic reinspection of the facility. Restaurants are encouraged to aim for scores approaching 100. Chinatown is apparently just aiming to pass. With an average score of 71, it’s meeting its goal.
Chinatown’s Average Score


The Limitations of our Dataset

We originally expected strong correlations between the number of restaurants in a given zip code and the population of that zip code, with an expectation that downtown would be an outlier (lots of restaurants, relatively few residents). When we graphed our data, we found that restaurant quantity and population were only weakly correlated, and we found a number of unexpected outliers.
Restaurant by Population Scatterplot

Similarly, we expected that the number of transit stops would be strongly correlated with the number of restaurants in a given zipcode. This time, our data supported our expectations, with a moderately strong correlation of 0.756.
Restaurant by Transit Scatterplot

Curiosity then led us to plot population versus number of transit stops for a given zipcode; again, the two were only weakly correlated, with many of the same outliers.
Transit by Population Scatterplot

This prompted a closer look at those outliers, and demonstrated a shortcoming in our dataset. It turns out that the outliers with large populations and few transit stops or restaurants are in the far suburbs of Austin. These areas are governed by other civic bodies, and thus the bulk of their restaurant inspections (and, potentially, transit) will be conducted by an entity other than the City of Austin. In order to get a cleaner view of the relationship between population, transit, and restaurant density, we would need to adjust our data to only include areas under the jurisdiction of the City of Austin. A good visualization of this distribution can be seen below.
Dataset Limitations Map


Restaurant Density and Non-native Population

The United States Census provides information on the number of residents per zipcode that are native citizens, as well as how many residents are naturalized citizens or noncitizens. For the purposes of this visualization, we’ve grouped “naturalized citizens” and “noncitizens” into one category, “non-native.” Would zipcodes with relatively high percentages of non-native residents be more or less restaurant-heavy than zipcodes with lower percentages of non-native residents? It turns out that zip codes with high percentages (in the case of this visualization, 25% or more) non-native residents do in fact have significantly more restaurants on average than other zipcodes.
Non-native Residents


Visualizations using Tableau

Boxplot using Tableau

Raw Scores- Histogram

As can be seen in the visualization below, the most common raw restaurant inspection score is between 90 and 100. The 90-95 and 95-100 bins are essentially the same. The second most common ranges are 85-90 and 100-105. These are also the same size, but a little over half the size of the most common score range.

Tableau: Raw Score Histogram

The next largest bin is half the size of the second largest, and this pattern continues until we drop below 70. This is particularly good news, as it implies that failing scores (those below 70) are not very common at all, and furthermore that exceptional scores are highly common.

CapMetro Stops and Restaurant Density as they Relate to Population- Scatterplot

Here we see a comprehensive visualization that reflects data as we’ve seen it before, in our “interesting things” section. This scatterplot shows restaurant and stop density per zipcode. Each point is sized by the population of that zipcode. Ultimately, we see an overall positive trend. However, upon closer examination, it is clear that many high population zipcodes have a lower restaurant and stop density.

Tableau: Restaurant and Stop Density Scatterplot

The implications of this have already been discussed in previous sections. However, it is also interesting to note that many zipcodes (regardless of population size), are grouped towards the lower to medium restaurant and stop density area. In fact, the further out in either direction you go, the less instances there are. This likely shows that while there is a slight positive correlation between stop and restaurant density, most areas are not likely to have an exceptional number of eihter.

Visualizations using Shiny in R

The screenshots and descriptions below are based on our interactive visualization app, accessible at https://kvaughn.shinyapps.io/restaurant_inspection/.

Boxplot Visualization using Shiny in R

One low score does not indicate a systemic problem with a restaurant’s cleanliness; before judging a restaurant with a low score, it behooves us to consider the other scores it has received. This boxplot allows the user to do just that. First select a cutoof point for scores, then choose a zipcode to see all restaurants that have scored below that level at least one. Each restaurant’s scores will display, giving the user an idea of whether the low score was a fluke or a sign of problems.

Shiny: Scores by Restaurant Data

Shiny: Scores by Restaurant Boxplot

Histogram Visualization using Shiny in R

This visualization allows the user to get a broader view of the restaurant inspection scores. The user is given the option to select scores from any combination of years. What’s interesting here is that the vast majority of restaurant inspections result in “passing” grades of 70 or higher.

Shiny: All Scores Data

Shiny: All Scores Histogram

Scatterplot Visualization using Shiny in R

The Scatterplot tab includes three separate visualizations drawn from one set of data. The first visualization plots the population of a zipcode against the number of restaurants in that zipcode. The second graph plots the population per zipcode against the quantity of transit stops in that zipcode. (Transit stop location information provided by Capital Metro and made available through data.texas.gov: https://data.texas.gov/dataset/GTFS/r4v4-vz24 ) As you see, the correlations between population and restaurant or transity-stop quantity are pretty weak. The third visualization in this set graphs transit stops by restaurants, and shows a much stronger correlation. See above for a discussion of one possible explanation for this pattern of relationships.

Shiny: Scatterplot Data

Shiny: Restaurant by Population Scatterplot

Shiny: Transit by Population Scatterplot

Shiny: Restaurant by Transit Scatterplot

Crosstab Visualizations using Shiny in R

Click here to be taken to our published Shiny app: https://kvaughn.shinyapps.io/restaurant_inspection/

Safety Index

This visualization starts with a somewhat-arbitrary KPI, the “Safety Index,” that takes into account both the average score and the lowest inspection score received for a given zip code in a given year. A high Safety Index indicates both a high average score and a high minimum score. Set the parameters however you like (3 and 8 are reasonable defaults) and check the crosstab to see each zip code’s ratings over the four-year period.

Shiny: Safety Index Data

Shiny: Safety Index Crosstab

Lowest Inspection Scores

This visualization allows the user to set an arbitrary cutoff point as an aid for identifying low inspection scores. The default value, 70, is the cutoff for restaurant inspections; lower scores will trigger a reinspection. After selecting a parameter using the slider and requesting data, the user can select the “Crosstab” tab to see which zip codes and years had unacceptably low inspection scores.

Shiny: Lowest Inspection Scores Data

Shiny: Lowest Inspection Scores Crosstab

People per Restaurant

Austin is a fast-growing city, and our restaurant scene is currently booming as well. This visualization allows a user to see where the density of restaurants compared to population is highest. Using a public population dataset generated by the US Census, we can find the number of people per restaurant in a given zip code; as more restaurants are added (or fail), the people-per-restaurant number changes. The default values highlight the density of restaurants in 78701, which is downtown Austin.

Shiny: People per Restaurant Data

Shiny: People per Restaurant Crosstab

Barchart Visualizations using Shiny in R

These visualizations are also accessible at https://kvaughn.shinyapps.io/restaurant_inspection/

Scores by Zip Code

Barcharts can be a good way to quickly identify trends visually. In this visualization, the user can create a set of zip codes of interest, then see each zipcode’s average score per year over the three or four years contained in the dataset.

Shiny: Scores by Zip Code Data

Shiny: Scores by Zip Code Bar Chart

Transit stops and restaurant density

Capital Metro, the Austin-area transit service, has made its data freely available for public download. By importing this data into geographic information software (ArcGIS) and overlaying the coordinates of transit stops on a shapefile of regional zip codes, we were able to count the number of transit stops per zip code. In this bar chart, we’re examining the relationship between transit density and restaurant density. Use the slider to select zip codes with more than the minimum number of transit stops, then compare the number of restaurants in these zip codes to the average number of restaurants per zip code throughout the region. The blue line is the calculated average for all of the selected zip codes, and the red is the grand average for all of the zipcodes in the Greater Austin area.

Shiny: Restaurant Density and Transit Stops Data

Shiny: Restaurant Density and Transit Stops Bar Chart

Nonnative residents and restaurant density

Would we expect zip codes with comparatively large numbers of nonnative (naturalized-citizen or noncitizen) residents to have more or fewer restaurants, on average, than zip codes with lower percentages of nonnative residents? This barchart allows the user to select a minimum percentage of nonnative residents per zip code, then shows the number of restaurants in that zip code and the average number of restaurants per zip code for all of the qualifying zip codes. This average can be compared to the grand average throughout the greater Austin area, shown in red.

Shiny: Restaurant Density and Nonnative Residents Data

Shiny: Restaurant Density and Nonnative Residents Bar Chart
LS0tCnRpdGxlOiAiQXVzdGluIFJlc3RhcmFudCBJbnNwZWN0aW9ucyIKYXV0aG9yOiAiPGNlbnRlcj48Yj5NYXJjdXMgTWFydGluZXogYW5kIEthdGUgVmF1Z2huPC9iPjwvY2VudGVyPiIKZGF0ZTogIjxjZW50ZXI+TWF5IDIsIDIwMTc8L2NlbnRlcj4iCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0Ci0tLQoKIyoqSW50cm9kdWN0aW9uKioKIEluIHRoaXMgcHJvamVjdCwgd2UncmUgZXhhbWluaW5nIGluc3BlY3Rpb24gc2NvcmVzIGZvciByZXN0YXVyYW50cyBpbiBhbmQgYXJvdW5kIEF1c3RpbiwgVGV4YXMsIGZyb20gMjAxNCB0aHJvdWdoIGVhcmx5IDIwMTcuICBTY29yZXMgYXJlIGRldGVybWluZWQgdGhyb3VnaCByb3V0aW5lIGluc3BlY3Rpb25zLCB1c3VhbGx5IGNvbmR1Y3RlZCB0d2ljZSBhIHllYXIuICBJZiBhIHNjb3JlIGxvd2VyIHRoYW4gNzAgaXMgcmVjb3JkZWQgaW4gYSB5ZWFybHkgaW5zcGVjdGlvbiwgdGhlIHJlc3RhdXJhbnQgd2lsbCBiZSBzdWJqZWN0ZWQgdG8gb25lIG9yIG1vcmUgZm9sbG93dXAgdmlzaXRzIHRvIGVuc3VyZSBhIHJldHVybiB0byBjb21wbGlhbmNlLiAgQWxsIG9mIG91ciByZXN0YXVyYW50IGluc3BlY3Rpb24gcmVjb3JkcyBpbmNsdWRlIGdlb2dyYXBoaWNhbCBpbmZvcm1hdGlvbiBpbiB0aGUgZm9ybSBvZiB6aXAgY29kZXMsIGFsbG93aW5nIHRoZSB1c2Ugb2YgYWRkaXRpb25hbCBkYXRhc2V0cyB0byBmdXJ0aGVyIGV4cGxvcmUgdGhlIGRhdGEuICBWaXNpdCBodHRwczovL2RhdGEud29ybGQva3ZhdWdobi9zLTE3LWR2LXByb2plY3QtNiB0byBleHBsb3JlIG91ciBkYXRhc2V0cywgb3Igc2VlIGJlbG93IGZvciB0aGUgdmlzdWFsaXphdGlvbnMgd2UndmUgbWFkZSBvZiB0aGUgZGF0YS4KCiMjKipSIENvbmZpZ3VyYXRpb24qKgpCZWxvdyB3ZSBkaXNwbGF5IG91ciBzZXNzaW9uSW5mbygpLgoKYGBge3IgU2Vzc2lvbkluZm8sIGVjaG89RkFMU0V9IApzZXNzaW9uSW5mbyhwYWNrYWdlPU5VTEwpCmBgYAoKIyoqVGhlIERhdGEqKgpUaGUgcmVzdGF1cmFudCBpbnNwZWN0aW9uIGRhdGFzZXQgd2FzIHByb3ZpZGVkIHRocm91Z2ggdGhlIENpdHkgb2YgQXVzdGluJ3MgT3BlbiBEYXRhIFBvcnRhbCwgaHR0cHM6Ly9kYXRhLmF1c3RpbnRleGFzLmdvdi8uICBUaGlzIGZyZWUgZG93bmxvYWQgaXMgYXZhaWxhYmxlIGluIG11bHRpcGxlIGZvcm1hdHMgYXQgaHR0cHM6Ly9kYXRhLmF1c3RpbnRleGFzLmdvdi9IZWFsdGgvUmVzdGF1cmFudC1JbnNwZWN0aW9uLVNjb3Jlcy91dGh3LWE3aWguICBGb3IgdGhpcyBwcm9qZWN0LCB3ZSBkb3dubG9hZGVkIGEgQ1NWIGZpbGUgYW5kIGNsZWFuZWQgaXQgdXNpbmcgdGhlIEV4dHJhY3QtVHJhbnNsYXRlLUxvYWQgcHJvY2VkdXJlIG91dGxpbmVkIGJlbG93LgoKIyoqRXh0cmFjdC1UcmFuc2xhdGUtTG9hZCAoRVRMKSoqClRoZSBkYXRhc2V0IHdlIHJlY2VpdmVkIG5lZWRlZCBzb21lIGNsZWFuaW5nLCBhcyBpdCB3YXMgdW5yZWFkYWJsZSB0byBUYWJsZWF1IGluIGl0cyBvcmlnaW5hbCBDU1YgZm9ybWF0dGluZy4gIFdlIHVzZWQgdGhlIEV4dHJhY3QtVHJhbnNsYXRlLUxvYWQgbWV0aG9kIGRpc2N1c3NlZCBpbiBjbGFzcywgYW5kIGJ1aWx0IGFuIFIgc2NyaXB0IGZvdW5kIGF0ICIuLi8wMSBEYXRhL0VUTFJlc3RhdXJhbnQuUiIgIFdlIGFsc28gY2xlYW5lZCB1cCB0aGUgam9pbiBxdWVyeSB1c2VkIGluIG91ciBUYWJsZWF1IHZpc3VhbGl6YXRpb25zOyBpdCBjYW4gYmUgZm91bmQgYXQgIi4uLzAxIERhdGEvRVRMUXVlcnkuUiIgIElmIHlvdSdkIGxpa2UgdG8gZm9sbG93IGFsb25nLCBoZXJlJ3MgaG93IHdlIHByb2Nlc3NlZCB0aGUgcmVzdGF1cmFudCBpbnNwZWN0aW9uIGRhdGE6CgojIypTdGVwLUJ5LVN0ZXAgSW5zdHJ1Y3Rpb25zKgoqKkZpcnN0LCBkb3dubG9hZCB0aGUgdW5jbGVhbmVkIENTVjogaHR0cHM6Ly9kYXRhLmF1c3RpbnRleGFzLmdvdi9hcGkvdmlld3MvZWNtdi05eHhpL3Jvd3MuY3N2P2FjY2Vzc1R5cGU9RE9XTkxPQUQuIFByZXBlbmQgIlByZUVUTF8iIHRvIHRoZSBmaWxlIG5hbWUsIGFuZCBwdXQgaXQgaW4gYSBmb2xkZXIgY2FsbGVkIENTVnMgaW4gdGhlIHNhbWUgZGlyZWN0b3J5IGFzIHRoaXMgcHJvamVjdCAoczE3ZHZwcm9qZWN0NS12YXVnaG4tY2FubmF0YS1tYXJ0aW5leikuKioKCiMjIypTdGVwIDE6IFNldCB1cCB0aGUgZW52aXJvbm1lbnQqCk5vdGUgdGhhdCB3ZSBoYXZlIG9uZSBjb2x1bW4gb2YgbnVtZXJpYyBkYXRhICgiU2NvcmUiKSwgb25lIGNvbHVtbiBvZiBkYXRlcyAoIkluc3BlY3Rpb24gRGF0ZSIpLCB0aHJlZSBjb2x1bW5zIG9mIHN0cmluZ3MgKCJSZXN0YXVyYW50IE5hbWUiLCAiQWRkcmVzcyIsIGFuZCAiUHJvY2VzcyBEZXNjcmlwdGlvbiIpLCBhbmQgdHdvIGNvbHVtbnMgb2YgbnVtZXJpYyBkYXRhIHVzZWQgY2F0ZWdvcmljYWxseSAoIlppcCBDb2RlIiBhbmQgIkZhY2lsaXR5IElEIikuICBGb3IgdGhlIHNha2Ugb2YgZWFzZSBvZiB1c2UsIHRoZXNlIGxhc3QgdHdvIGNvbHVtbnMgd2lsbCBiZSB0cmVhdGVkIGFzIHN0cmluZ3MuCmBgYHtyIGV0bDF9CiMgU2V0IHdvcmtpbmcgZGlyZWN0b3J5CnNldHdkKCJ+L3MxN2R2ZmluYWxwcm9qZWN0LXZhdWdobi1jYW5uYXRhLW1hcnRpbmV6LTEvMDAgRG9jcyIpCgojIFNldCBmaWxlcGF0aApmaWxlX3BhdGggPSAiLi4vLi4vQ1NWcy9QcmVFVExfUmVzdGF1cmFudF9JbnNwZWN0aW9uX1Njb3Jlcy5jc3YiCgojIENyZWF0ZSBkYXRhZnJhbWUgZnJvbSBvcmlnaW5hbCBDU1YKZGYgPC0gcmVhZC5jc3YoZmlsZV9wYXRoLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIFN0YW5kYXJkaXplIGNvbHVtbiBuYW1lcwpuYW1lcyhkZikgPC0gZ3N1YigiXFwuKyIsICIgIiwgbmFtZXMoZGYpKQoKIyBQcmludCBjb2x1bW4gbmFtZXMgYW5kIHR5cGVzCnN0cihkZikKYGBgCgojIyMqU3RlcCAyOiBDb2xsZWN0IGNvbHVtbnMgYnkgdHlwZSoKV2UndmUgZ3JvdXBlZCB0aGUgZGF0ZSBjb2x1bW4gc2VwYXJhdGVseSBmcm9tIG1lYXN1cmVzIGFuZCBkaW1lbnNpb25zOyB3aGlsZSBUYWJsZWF1IHdpbGwgcmVjb2duaXplIHRoZXNlIGRhdGEgYXMgZGF0ZXMsIGl0IHNlZW1zIHBydWRlbnQgdG8gcmVjbGFzc2lmeSB0aGVtIGludG8gYSBzdGFuZGFyZGl6ZWQgZm9ybWF0LgpgYGB7ciBldGwyfQojIFNlbGVjdCBzdHJpbmcgZGF0YSBhcyAnZGltZW5zaW9ucycKZGltZW5zaW9ucyA8LSBjKCJSZXN0YXVyYW50IE5hbWUiLCAiWmlwIENvZGUiLCAiQWRkcmVzcyIsICJQcm9jZXNzIERlc2NyaXB0aW9uIiwgIkZhY2lsaXR5IElEIikKCiMgU2VsZWN0IGRhdGVzIGFzICdkYXRlcycKZGF0ZXMgPC0gYygiSW5zcGVjdGlvbiBEYXRlIikKCiMgU2VsZWN0IGFsbCByZW1haW5pbmcgZGF0YSBhcyAnbWVhc3VyZXMnCm1lYXN1cmVzIDwtIHNldGRpZmYobmFtZXMoZGYpLCB1bmlvbihkaW1lbnNpb25zLCBkYXRlcykpCgpgYGAKCiMjIypTdGVwIDM6IFJlbW92ZSBzcGVjaWFsIGNoYXJhY3RlcnMqCkhlcmUgd2UgcmVtb3ZlIHNwZWNpYWwgY2hhcmFjdGVycyBmcm9tIGFsbCBvZiBvdXIgZGF0YS4gIFRoZXNlIGNoYXJhY3RlcnMgY2FuIHNlcnZlIG5vIHB1cnBvc2UgaW4gdGhlIGRhdGEsIGFuZCBtaWdodCBjYXVzZSBwcm9ibGVtcyBpbiB0aGUgYW5hbHlzaXMgcHJvY2Vzcy4gIFRvIGltcHJvdmUgcmVhZGFiaWxpdHksIHNwZWNpYWwgY2hhcmFjdGVycyBoYXZlIGJlZW4gcmVwbGFjZWQgYnkgc3BhY2VzLgpgYGB7ciBldGwzfQojIEdldCByaWQgb2Ygc3BlY2lhbCBjaGFyYWN0ZXJzIGluIGVhY2ggY29sdW1uLgpmb3IobiBpbiBuYW1lcyhkZikpIHsKICBkZltuXSA8LSBkYXRhLmZyYW1lKGxhcHBseShkZltuXSwgZ3N1YiwgcGF0dGVybj0iW14gLX5dIixyZXBsYWNlbWVudD0gIiAiKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQp9CmBgYAoKIyMjKlN0ZXAgNDogTW9kaWZ5IHJlY29yZHMgaW4gZGltZW5zaW9ucyoKTm93IHdlIGdvIHRocm91Z2ggYWxsIG9mIHRoZSBjaGFyYWN0ZXItYmFzZWQgY29sdW1ucyAoZ3JvdXBlZCBhcyBkaW1lbnNpb25zKSBhbmQgcmVtb3ZlIHRyb3VibGVzb21lIGNoYXJhY3RlcnMuICBBbXBlcnNhbmRzIGFyZSByZXBsYWNlZCB3aXRoICJhbmQiLCBzZW1pY29sb25zIGFyZSByZXBsYWNlZCB3aXRoIGNvbG9ucywgYW5kIHNpbmdsZS0gYW5kIGRvdWJsZS1xdW90ZXMgYXJlIHJlbW92ZWQgb3V0cmlnaHQuICBEYXRhIG9mIE5BIChudWxsKSBpcyByZXBsYWNlZCB3aXRoIGFuIGVtcHR5IHN0cmluZy4KYGBge3IgZXRsNH0KIyBUaGlzIGZ1bmN0aW9uIHdpbGwgcmVwbGFjZSBOQSBkYXRhIHdpdGggYW4gZW1wdHkgc3RyaW5nCm5hMmVtcHR5U3RyaW5nIDwtIGZ1bmN0aW9uICh4KSB7CiAgeFtpcy5uYSh4KV0gPC0gIiIKICByZXR1cm4oeCkKfQojIFdlJ2xsIGFwcGx5IHRoaXMgdG8gYWxsIGNvbHVtbnMgZ3JvdXBlZCBhcyBkaW1lbnNpb25zCmlmKCBsZW5ndGgoZGltZW5zaW9ucykgPiAwKSB7CiAgZm9yKGQgaW4gZGltZW5zaW9ucykgewogICAgIyBDaGFuZ2UgTkEgdG8gdGhlIGVtcHR5IHN0cmluZy4KICAgIGRmW2RdIDwtIGRhdGEuZnJhbWUobGFwcGx5KGRmW2RdLCBuYTJlbXB0eVN0cmluZyksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKICAgICMgR2V0IHJpZCBvZiAiIGFuZCAnIGluIGRpbWVuc2lvbnMuCiAgICBkZltkXSA8LSBkYXRhLmZyYW1lKGxhcHBseShkZltkXSwgZ3N1YiwgcGF0dGVybj0iW1wiJ10iLHJlcGxhY2VtZW50PSAiIiksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKICAgICMgQ2hhbmdlICYgdG8gYW5kIGluIGRpbWVuc2lvbnMuCiAgICBkZltkXSA8LSBkYXRhLmZyYW1lKGxhcHBseShkZltkXSwgZ3N1YiwgcGF0dGVybj0iJiIscmVwbGFjZW1lbnQ9ICIgYW5kICIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgICAjIENoYW5nZSA6IHRvIDsgaW4gZGltZW5zaW9ucy4KICAgIGRmW2RdIDwtIGRhdGEuZnJhbWUobGFwcGx5KGRmW2RdLCBnc3ViLCBwYXR0ZXJuPSI6IixyZXBsYWNlbWVudD0gIjsiKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQogIH0KfQoKYGBgCgojIyMqU3RlcCA1OiBNb2RpZnkgZGF0ZXMqCkhlcmUgd2UgZW5zdXJlIHRoYXQgZGF0ZXMgYXJlIGZvcm1hdHRlZCBjb3JyZWN0bHkuCmBgYHtyIGV0bDV9CmlmKCBsZW5ndGgoZGF0ZXMpID4gMSB8fCAhIGlzLm5hKGRhdGVzKSkgewogIGZvcih5IGluIGRhdGVzKSB7CiAgICAjIEZvcm1hdCBhcyBkYXRlcwogICAgZGZbeV0gPC0gZGF0YS5mcmFtZShsYXBwbHkoZGZbeV0sIGZ1bmN0aW9uKHkpIGFzLkRhdGUoeSwgZm9ybWF0ID0gIiVtLyVkLyV5IikpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgfQp9CmBgYAoKIyMjKlN0ZXAgNjogTW9kaWZ5IG1lYXN1cmVzKgpOb3cgd2UgdGFrZSBhbGwgb2YgdGhlIG5vbi1udW1lcmljIGNoYXJhY3RlcnMgb3V0IG9mIG91ciBtZWFzdXJlcy4KYGBge3IgZXRsNn0KbmEyemVybyA8LSBmdW5jdGlvbiAoeCkgewogIHhbaXMubmEoeCldIDwtIDAKICByZXR1cm4oeCkKfQojIEdldCByaWQgb2YgYWxsIGNoYXJhY3RlcnMgaW4gbWVhc3VyZXMgZXhjZXB0IGZvciBudW1iZXJzLCB0aGUgLSBzaWduLCBhbmQgcGVyaW9kLmRpbWVuc2lvbnMsIGFuZCBjaGFuZ2UgTkEgdG8gMC4KaWYobGVuZ3RoKG1lYXN1cmVzKSA+IDEgfHwgISBpcy5uYShtZWFzdXJlcykpIHsKICBmb3IobSBpbiBtZWFzdXJlcykgewogICAgZGZbbV0gPC0gZGF0YS5mcmFtZShsYXBwbHkoZGZbbV0sIGdzdWIsIHBhdHRlcm49IlteLS0uMC05XSIscmVwbGFjZW1lbnQ9IiIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgICBkZlttXSA8LSBkYXRhLmZyYW1lKGxhcHBseShkZlttXSwgbmEyemVybyksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKICAgIGRmW21dIDwtIGRhdGEuZnJhbWUobGFwcGx5KGRmW21dLCBmdW5jdGlvbihtKSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihtKSkpKSAjIFRoaXMgaXMgbmVlZGVkIHRvIHR1cm4gbWVhc3VyZXMgYmFjayB0byBudW1lcmljIGJlY2F1c2UgZ3N1YiB0dXJucyB0aGVtIGludG8gc3RyaW5ncy4KICB9Cn0KYGBgCgojIyMqU3RlcCA3OiBEdW1teSBjaGVjayoKQWx3YXlzIGEgdXNlZnVsIHRoaW5nLiAgTGV0J3MgbG9vayBhdCBvdXIgZGF0YSBhbmQgc2VlIHdoYXQgd2UndmUgZ290LiAgV2UncmUgZXhwZWN0aW5nIGFsbCBkYXRhIHRvIGJlIGluIGNoYXJhY3RlciBmb3JtIGV4Y2VwdCAiU2NvcmUiLCB3aGljaCB3aWxsIGJlIG51bWVyaWMsIGFuZCBvdXIgZGF0ZSBjb2x1bW4gbmFtZWQgIkluc3BlY3Rpb24gRGF0ZSIuCmBgYHtyIGV0bDd9CiMgVGFrZSBhIGxvb2sgYW5kIG1ha2Ugc3VyZSBpdCdzIHdoYXQgeW91IHRoaW5rIGl0IHNob3VsZCBiZToKcHJpbnQoc3VtbWFyeShkZikpCmBgYAoKIyMjKlN0ZXAgODogV3JpdGUgdG8gYSBuZXcgZmlsZSoKT3VyIGRhdGEgbG9va3MgZ29vZCwgYW5kIHdlIG5lZWQgdG8gd3JpdGUgaXQgdG8gYSBuZXcgZmlsZS4KYGBge3IgZXRsOH0KIyBOb3cgd3JpdGUgaXQgdG8gYSBuZXcgY2xlYW4gZmlsZS4Kd3JpdGUuY3N2KGRmLCBnc3ViKCJQcmVFVExfIiwgIiIsIGZpbGVfcGF0aCksIHJvdy5uYW1lcz1GQUxTRSwgbmEgPSAiIikKYGBgCgojKipWaXN1YWxpemF0aW9ucyoqCgojIyoqSW50ZXJlc3RpbmcgVGhpbmdzKioKIyMjKipDaGluYXRvd24qKiAgCkdlbmVyYWxseSBzcGVha2luZywgbG93IHNjb3JlcyBhcmUgb3V0bGllcnMgZm9yIHJlc3RhdXJhbnRzLiAgVGhlIGluc3BlY3RvciBjYXVnaHQgdGhlbSBvbiBhIGJhZCBkYXksIHBlcmhhcHMuICBMb29rIGF0IHRoZSBoaXN0b2dyYW0gZm9yIGFuIGluZGljYXRpb24gb2YgdGhlIHByb3BvcnRpb24gb2YgcGFzc2luZyBzY29yZXMgKGFib3ZlIDcwKSB2ZXJzdXMgZmFpbGluZyBzY29yZXMuICAKPGNlbnRlcj4hW0FsbCBTY29yZXMgSGlzdG9ncmFtXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TSGlzdEIucG5nKTwvY2VudGVyPgo8YnI+CklmIHlvdSdyZSBpbnRlcmVzdGVkIGluIHNlZWluZyB0aGUgd2hvbGUgY29sbGVjdGlvbiBvZiBzY29yZXMgZm9yIGEgcmVzdGF1cmFudCB3aXRoIGF0IGxlYXN0IG9uZSBsb3cgc2NvcmUsIHVzZSBvdXIgU2hpbnkgYm94cGxvdCBhbmQgc2VsZWN0IHRoZSB6aXBjb2RlIG9mIGludGVyZXN0LiAgU29tZSByZXN0YXVyYW50cyBkZW1vbnN0cmF0ZSBhIHRyZW5kIGluIHRoZWlyIGxvdyBzY29yZXMgdGhhdCBnb2VzIGJleW9uZCAib25lIGJhZCBkYXkiLiAgQ2hpbmF0b3duLCBpbiA3ODczMSwgaXMgYSBnb29kIGV4YW1wbGUgb2YgdGhpcy4gIEEgc2NvcmUgb2YgNzAgb3IgaGlnaGVyIGlzIGNvbnNpZGVyZWQgJ3Bhc3NpbmcsJyB3aGlsZSBhIHNjb3JlIGJlbG93IDcwIHRyaWdnZXJzIGFuIGF1dG9tYXRpYyByZWluc3BlY3Rpb24gb2YgdGhlIGZhY2lsaXR5LiAgUmVzdGF1cmFudHMgYXJlIGVuY291cmFnZWQgdG8gYWltIGZvciBzY29yZXMgYXBwcm9hY2hpbmcgMTAwLiAgQ2hpbmF0b3duIGlzIGFwcGFyZW50bHkganVzdCBhaW1pbmcgdG8gcGFzcy4gIFdpdGggYW4gYXZlcmFnZSBzY29yZSBvZiA3MSwgaXQncyBtZWV0aW5nIGl0cyBnb2FsLgo8Y2VudGVyPiFbQ2hpbmF0b3duJ3MgQXZlcmFnZSBTY29yZV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0JveEIucG5nKTwvY2VudGVyPgo8YnI+CgojIyMqKlRoZSBMaW1pdGF0aW9ucyBvZiBvdXIgRGF0YXNldCoqIApXZSBvcmlnaW5hbGx5IGV4cGVjdGVkIHN0cm9uZyBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIHJlc3RhdXJhbnRzIGluIGEgZ2l2ZW4gemlwIGNvZGUgYW5kIHRoZSBwb3B1bGF0aW9uIG9mIHRoYXQgemlwIGNvZGUsIHdpdGggYW4gZXhwZWN0YXRpb24gdGhhdCBkb3dudG93biB3b3VsZCBiZSBhbiBvdXRsaWVyIChsb3RzIG9mIHJlc3RhdXJhbnRzLCByZWxhdGl2ZWx5IGZldyByZXNpZGVudHMpLiAgV2hlbiB3ZSBncmFwaGVkIG91ciBkYXRhLCB3ZSBmb3VuZCB0aGF0IHJlc3RhdXJhbnQgcXVhbnRpdHkgYW5kIHBvcHVsYXRpb24gd2VyZSBvbmx5IHdlYWtseSBjb3JyZWxhdGVkLCBhbmQgd2UgZm91bmQgYSBudW1iZXIgb2YgdW5leHBlY3RlZCBvdXRsaWVycy4gIAo8Y2VudGVyPiFbUmVzdGF1cmFudCBieSBQb3B1bGF0aW9uIFNjYXR0ZXJwbG90XSguLi8wMyBWaXN1YWxpemF0aW9ucy9TU2NhdHRlcjEucG5nKTwvY2VudGVyPgo8YnI+ClNpbWlsYXJseSwgd2UgZXhwZWN0ZWQgdGhhdCB0aGUgbnVtYmVyIG9mIHRyYW5zaXQgc3RvcHMgd291bGQgYmUgc3Ryb25nbHkgY29ycmVsYXRlZCB3aXRoIHRoZSBudW1iZXIgb2YgcmVzdGF1cmFudHMgaW4gYSBnaXZlbiB6aXBjb2RlLiAgVGhpcyB0aW1lLCBvdXIgZGF0YSBzdXBwb3J0ZWQgb3VyIGV4cGVjdGF0aW9ucywgd2l0aCBhIG1vZGVyYXRlbHkgc3Ryb25nIGNvcnJlbGF0aW9uIG9mIDAuNzU2LiAgCjxjZW50ZXI+IVtSZXN0YXVyYW50IGJ5IFRyYW5zaXQgU2NhdHRlcnBsb3RdKC4uLzAzIFZpc3VhbGl6YXRpb25zL1NTY2F0dGVyMy5wbmcpPC9jZW50ZXI+Cjxicj4KQ3VyaW9zaXR5IHRoZW4gbGVkIHVzIHRvIHBsb3QgcG9wdWxhdGlvbiB2ZXJzdXMgbnVtYmVyIG9mIHRyYW5zaXQgc3RvcHMgZm9yIGEgZ2l2ZW4gemlwY29kZTsgYWdhaW4sIHRoZSB0d28gd2VyZSBvbmx5IHdlYWtseSBjb3JyZWxhdGVkLCB3aXRoIG1hbnkgb2YgdGhlIHNhbWUgb3V0bGllcnMuICAKPGNlbnRlcj4hW1RyYW5zaXQgYnkgUG9wdWxhdGlvbiBTY2F0dGVycGxvdF0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU1NjYXR0ZXIyLnBuZyk8L2NlbnRlcj4gCjxicj4KVGhpcyBwcm9tcHRlZCBhIGNsb3NlciBsb29rIGF0IHRob3NlIG91dGxpZXJzLCBhbmQgZGVtb25zdHJhdGVkIGEgc2hvcnRjb21pbmcgaW4gb3VyIGRhdGFzZXQuICBJdCB0dXJucyBvdXQgdGhhdCB0aGUgb3V0bGllcnMgd2l0aCBsYXJnZSBwb3B1bGF0aW9ucyBhbmQgZmV3IHRyYW5zaXQgc3RvcHMgb3IgcmVzdGF1cmFudHMgYXJlIGluIHRoZSBmYXIgc3VidXJicyBvZiBBdXN0aW4uICBUaGVzZSBhcmVhcyBhcmUgZ292ZXJuZWQgYnkgb3RoZXIgY2l2aWMgYm9kaWVzLCBhbmQgdGh1cyB0aGUgYnVsayBvZiB0aGVpciByZXN0YXVyYW50IGluc3BlY3Rpb25zIChhbmQsIHBvdGVudGlhbGx5LCB0cmFuc2l0KSB3aWxsIGJlIGNvbmR1Y3RlZCBieSBhbiBlbnRpdHkgb3RoZXIgdGhhbiB0aGUgQ2l0eSBvZiBBdXN0aW4uICBJbiBvcmRlciB0byBnZXQgYSBjbGVhbmVyIHZpZXcgb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBvcHVsYXRpb24sIHRyYW5zaXQsIGFuZCByZXN0YXVyYW50IGRlbnNpdHksIHdlIHdvdWxkIG5lZWQgdG8gYWRqdXN0IG91ciBkYXRhIHRvIG9ubHkgaW5jbHVkZSBhcmVhcyB1bmRlciB0aGUganVyaXNkaWN0aW9uIG9mIHRoZSBDaXR5IG9mIEF1c3Rpbi4gCkEgZ29vZCB2aXN1YWxpemF0aW9uIG9mIHRoaXMgZGlzdHJpYnV0aW9uIGNhbiBiZSBzZWVuIGJlbG93Lgo8Y2VudGVyPiFbRGF0YXNldCBMaW1pdGF0aW9ucyBNYXBdKC4uLzAzIFZpc3VhbGl6YXRpb25zL1RCT3V0bGllck1hcC5wbmcpPC9jZW50ZXI+Cjxicj4KCiMjIyoqUmVzdGF1cmFudCBEZW5zaXR5IGFuZCBOb24tbmF0aXZlIFBvcHVsYXRpb24qKgpUaGUgVW5pdGVkIFN0YXRlcyBDZW5zdXMgcHJvdmlkZXMgaW5mb3JtYXRpb24gb24gdGhlIG51bWJlciBvZiByZXNpZGVudHMgcGVyIHppcGNvZGUgdGhhdCBhcmUgbmF0aXZlIGNpdGl6ZW5zLCBhcyB3ZWxsIGFzIGhvdyBtYW55IHJlc2lkZW50cyBhcmUgbmF0dXJhbGl6ZWQgY2l0aXplbnMgb3Igbm9uY2l0aXplbnMuICBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgdmlzdWFsaXphdGlvbiwgd2UndmUgZ3JvdXBlZCAibmF0dXJhbGl6ZWQgY2l0aXplbnMiIGFuZCAibm9uY2l0aXplbnMiIGludG8gb25lIGNhdGVnb3J5LCAibm9uLW5hdGl2ZS4iICBXb3VsZCB6aXBjb2RlcyB3aXRoIHJlbGF0aXZlbHkgaGlnaCBwZXJjZW50YWdlcyBvZiBub24tbmF0aXZlIHJlc2lkZW50cyBiZSBtb3JlIG9yIGxlc3MgcmVzdGF1cmFudC1oZWF2eSB0aGFuIHppcGNvZGVzIHdpdGggbG93ZXIgcGVyY2VudGFnZXMgb2Ygbm9uLW5hdGl2ZSByZXNpZGVudHM/ICBJdCB0dXJucyBvdXQgdGhhdCB6aXAgY29kZXMgd2l0aCBoaWdoIHBlcmNlbnRhZ2VzIChpbiB0aGUgY2FzZSBvZiB0aGlzIHZpc3VhbGl6YXRpb24sIDI1JSBvciBtb3JlKSBub24tbmF0aXZlIHJlc2lkZW50cyBkbyBpbiBmYWN0IGhhdmUgc2lnbmlmaWNhbnRseSBtb3JlIHJlc3RhdXJhbnRzIG9uIGF2ZXJhZ2UgdGhhbiBvdGhlciB6aXBjb2Rlcy4KPGNlbnRlcj4hW05vbi1uYXRpdmUgUmVzaWRlbnRzXSguLi8wMyBWaXN1YWxpemF0aW9ucy9Ob25uYXRpdmUucG5nKTwvY2VudGVyPgo8YnI+CgoKIyMqKlZpc3VhbGl6YXRpb25zIHVzaW5nIFRhYmxlYXUqKgoKIyMjKipCb3hwbG90IHVzaW5nIFRhYmxlYXUqKgoKIyMjKipSYXcgU2NvcmVzLSBIaXN0b2dyYW0qKgpBcyBjYW4gYmUgc2VlbiBpbiB0aGUgdmlzdWFsaXphdGlvbiBiZWxvdywgdGhlIG1vc3QgY29tbW9uIHJhdyByZXN0YXVyYW50IGluc3BlY3Rpb24gc2NvcmUgaXMgYmV0d2VlbiA5MCBhbmQgMTAwLiBUaGUgOTAtOTUgYW5kIDk1LTEwMCBiaW5zIGFyZSBlc3NlbnRpYWxseSB0aGUgc2FtZS4gVGhlIHNlY29uZCBtb3N0IGNvbW1vbiByYW5nZXMgYXJlIDg1LTkwIGFuZCAxMDAtMTA1LiBUaGVzZSBhcmUgYWxzbyB0aGUgc2FtZSBzaXplLCBidXQgYSBsaXR0bGUgb3ZlciBoYWxmIHRoZSBzaXplIG9mIHRoZSBtb3N0IGNvbW1vbiBzY29yZSByYW5nZS4gCgo8Y2VudGVyPiFbVGFibGVhdTogUmF3IFNjb3JlIEhpc3RvZ3JhbV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvVEhpc3QucG5nKTwvY2VudGVyPgoKVGhlIG5leHQgbGFyZ2VzdCBiaW4gaXMgaGFsZiB0aGUgc2l6ZSBvZiB0aGUgc2Vjb25kIGxhcmdlc3QsIGFuZCB0aGlzIHBhdHRlcm4gY29udGludWVzIHVudGlsIHdlIGRyb3AgYmVsb3cgNzAuIFRoaXMgaXMgcGFydGljdWxhcmx5IGdvb2QgbmV3cywgYXMgaXQgaW1wbGllcyB0aGF0IGZhaWxpbmcgc2NvcmVzICh0aG9zZSBiZWxvdyA3MCkgYXJlIG5vdCB2ZXJ5IGNvbW1vbiBhdCBhbGwsIGFuZCBmdXJ0aGVybW9yZSB0aGF0IGV4Y2VwdGlvbmFsIHNjb3JlcyBhcmUgaGlnaGx5IGNvbW1vbi4KCiMjIyoqQ2FwTWV0cm8gU3RvcHMgYW5kIFJlc3RhdXJhbnQgRGVuc2l0eSBhcyB0aGV5IFJlbGF0ZSB0byBQb3B1bGF0aW9uLSBTY2F0dGVycGxvdCoqCkhlcmUgd2Ugc2VlIGEgY29tcHJlaGVuc2l2ZSB2aXN1YWxpemF0aW9uIHRoYXQgcmVmbGVjdHMgZGF0YSBhcyB3ZSd2ZSBzZWVuIGl0IGJlZm9yZSwgaW4gb3VyICJpbnRlcmVzdGluZyB0aGluZ3MiIHNlY3Rpb24uIFRoaXMgc2NhdHRlcnBsb3Qgc2hvd3MgcmVzdGF1cmFudCBhbmQgc3RvcCBkZW5zaXR5IHBlciB6aXBjb2RlLiBFYWNoIHBvaW50IGlzIHNpemVkIGJ5IHRoZSBwb3B1bGF0aW9uIG9mIHRoYXQgemlwY29kZS4gVWx0aW1hdGVseSwgd2Ugc2VlIGFuIG92ZXJhbGwgcG9zaXRpdmUgdHJlbmQuIEhvd2V2ZXIsIHVwb24gY2xvc2VyIGV4YW1pbmF0aW9uLCBpdCBpcyBjbGVhciB0aGF0IG1hbnkgaGlnaCBwb3B1bGF0aW9uIHppcGNvZGVzIGhhdmUgYSBsb3dlciByZXN0YXVyYW50IGFuZCBzdG9wIGRlbnNpdHkuIAoKPGNlbnRlcj4hW1RhYmxlYXU6IFJlc3RhdXJhbnQgYW5kIFN0b3AgRGVuc2l0eSBTY2F0dGVycGxvdF0oLi4vMDMgVmlzdWFsaXphdGlvbnMvVEJTY2F0dGVycGxvdC5wbmcpPC9jZW50ZXI+CgpUaGUgaW1wbGljYXRpb25zIG9mIHRoaXMgaGF2ZSBhbHJlYWR5IGJlZW4gZGlzY3Vzc2VkIGluIHByZXZpb3VzIHNlY3Rpb25zLiBIb3dldmVyLCBpdCBpcyBhbHNvIGludGVyZXN0aW5nIHRvIG5vdGUgdGhhdCBtYW55IHppcGNvZGVzIChyZWdhcmRsZXNzIG9mIHBvcHVsYXRpb24gc2l6ZSksIGFyZSBncm91cGVkIHRvd2FyZHMgdGhlIGxvd2VyIHRvIG1lZGl1bSByZXN0YXVyYW50IGFuZCBzdG9wIGRlbnNpdHkgYXJlYS4gSW4gZmFjdCwgdGhlIGZ1cnRoZXIgb3V0IGluIGVpdGhlciBkaXJlY3Rpb24geW91IGdvLCB0aGUgbGVzcyBpbnN0YW5jZXMgdGhlcmUgYXJlLiBUaGlzIGxpa2VseSBzaG93cyB0aGF0IHdoaWxlIHRoZXJlIGlzIGEgc2xpZ2h0IHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gc3RvcCBhbmQgcmVzdGF1cmFudCBkZW5zaXR5LCBtb3N0IGFyZWFzIGFyZSBub3QgbGlrZWx5IHRvIGhhdmUgYW4gZXhjZXB0aW9uYWwgbnVtYmVyIG9mIGVpaHRlci4gCgojIyMqKkNyb3NzdGFiLXJlbGF0ZWQgVmlzdWFsaXphdGlvbnMgdXNpbmcgVGFibGVhdSoqCkJlbG93IHlvdSB3aWxsIGZpbmQgdGhlIHZpc3VhbGl6YXRpb25zIHdlIGNyZWF0ZWQgdXNpbmcgVGFibGVhdS4gRWFjaCB2aXN1YWxpemF0aW9uIGlzIG9ubHkgYSBmcmFjdGlvbiBvZiB0aGUgaW5mb3JtYXRpb24gdGhhdCBjYW4gYmUgdmlld2VkIGluIFRhYmxlYXUsIGFzIHRoZXNlIGNyb3NzdGFicyBjYW5ub3Qgc2hvd2Nhc2UgYWxsIHRoZSBpbmZvcm1hdGlvbiBhdmFpbGFibGUgYXQgb25jZS4gIE91ciBUYWJsZWF1IHdvcmtib29rIGlzIGluY2x1ZGVkIGluIG91ciByZXBvc2l0b3J5IGluIHRoZSBmb2xkZXIgMDEgRGF0YS4KCiMjIyMqSW5zcGVjdGlvbiBTY29yZXMsIEFyZWEsIGFuZCBJbmNvbWUqClRoaXMgY3Jvc3N0YWIgc2hvd3MgYnkgeWVhciBhbmQgemlwY29kZSAoaW4gQXVzdGluKSwgdGhlIGF2ZXJhZ2UgcmVzdGF1cmFudCBpbnNwZWN0aW9uIHNjb3JlLiBUaGUgY3Jvc3N0YWIgaXMgY29sb3JlZCBieSB0aGUgcGVyY2VudGFnZSBvZiBob3VzZWhvbGRzIGluIGVhY2ggYXJlYSB1bmRlciB0aGUgbmF0aW9uYWwgcG92ZXJ0eSBsaW5lIChwdWxsZWQgZnJvbSBVUyBDZW5zdXMgZGF0YSkuIEFzIGlzIGV2aWRlbnQsIGF2ZXJhZ2Ugc2NvcmVzIHJlbWFpbiByZWxhdGl2ZWx5IGhpZ2ggYWNyb3NzIHBvdmVydHkgbGV2ZWxzIGFuZCB6aXBjb2Rlcy4gSW4gVGFibGVhdSB5b3UgYXJlIGFibGUgdG8gY3ljbGUgdGhyb3VnaCB6aXBjb2RlcyBpbiB0aGUgd2VzdGVybiBvciBlYXN0ZXJuIGhhbGYgb2YgdGhlIGdyZWF0ZXIgQXVzdGluIGFyZWEuIEV2ZW4gYXQgdGhpcyBsZXZlbCwgYXZlcmFnZSBzY29yZXMgcmVtYWluIHNpbWlsYXIuIFRoZXJlIGFyZSBtb3JlIGF2ZXJhZ2Ugc2NvcmVzIGJlbG93IDkwIGluIHRoZSBlYXN0ZXJuIHNlY3Rpb24sIGJ1dCB0aGlzIGlzIGxpa2VseSBub3Qgc2lnbmlmaWNhbnQuCgo8Y2VudGVyPiFbVGFibGVhdTogU2NvcmVzIGJ5IEluY29tZSBhbmQgQXJlYV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvQ3Jvc3N0YWJBdmVyYWdlU2NvcmVieVBvdmVydHlMZXZlbC5wbmcpPC9jZW50ZXI+CgpJdCBpcyBwb3NzaWJsZSB0aGlzIGlzIHVuaXF1ZSB0byBBdXN0aW4sIGFuZCBtYXkgYmUgYSBjb25zZXF1ZW5jZSBvZiBzdHJpbmdlbnQgZm9vZCBzYWZldHkgY29kZSBpbiB0aGVzZSBhcmVhcy4gRnVydGhlciBhbmFseXNpcyB3b3VsZCBuZWVkIHRvIGJlIGRvbmUgdG8gc2VlIGlmIHRoZXNlIGNvcnJlbGF0aW9ucyBhcmUgdHJ1ZSBlbHNld2hlcmUgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuCgojIyMjKkF2ZXJhZ2UgSW5zcGVjdGlvbiBTY29yZXMgR2VvZ3JhcGhpY2FsbHkqCkFzIGNhbiBiZSBzZWVuLCB0aGlzIHZpc3VhbGl6YXRpb24gZGlzcGxheXMgdGhlIGF2ZXJhZ2UgaW5zcGVjdGlvbnMgc2NvcmUgZm9yIGVhY2ggemlwY29kZSBhcmVhLiBFYWNoIHppcGNvZGUncyBjb2xvciBpcyBkZXRlcm1pbmVkIGJ5IGl0cyBhdmVyYWdlIGluc3BlY3Rpb24gc2NvcmUncyBwcm94aW1pdHkgdG8gdGhlIGdyYW5kIGF2ZXJhZ2UgZm9yIHRoZSB5ZWFyKHMpIHNlbGVjdGVkIGluIHRoZSBmaWx0ZXIuICBUaGlzIGlzIGRvbmUgdXNpbmcgYSBjYWxjdWxhdGVkIGZpZWxkLCBhbmQgd2lsbCBiZSByZWNhbGN1bGF0ZWQgYWNjb3JkaW5nIHRoZSB0aGUgZGF0YSBzZWxlY3RlZCBpbiB0aGUgWWVhciBmaWx0ZXIuICBJZiBhcnJpdmluZyBhdCB0aGlzIG1hcCBieSBjbGlja2luZyBvbiBlaXRoZXIgb2YgdGhlIGNyb3NzdGFicywgdGhlIHppcCBjb2RlcyB3aWxsIGRpc3BsYXkgdGhlIGRpZmZlcmVuY2UgZnJvbSB0aGUgZ3JhbmQgYXZlcmFnZSBvZiB0aGUgc2VsZWN0ZWQgeWVhci4KCjxjZW50ZXI+IVtUYWJsZWF1OiBNYXAgb2YgQXZlcmFnZSBJbnNwZWN0aW9uIFNjb3Jlc10oLi4vMDMgVmlzdWFsaXphdGlvbnMvQ3Jvc3N0YWJJbnNwZWN0aW9uU2NvcmVNYXAucG5nKTwvY2VudGVyPgoKSXQgaXMgYWdhaW4gZXZpZGVudCB0aGF0IGF2ZXJhZ2Ugc2NvcmVzIGFyZSByZWxhdGl2ZWx5IGhpZ2ggYWNyb3NzIGVhY2ggYXJlYS4gCgojIyMjKkF2ZXJhZ2UgU2NvcmUgYnkgWWVhcioKVGhpcyBoaWdobHkgY29tcHJlaGVuc2l2ZSB2aXN1YWxpemF0aW9uIHNob3dzIHVzIHRocmVlIG1haW4gcGllY2VzIG9mIGluZm9ybWF0aW9uOiBhdmVyYWdlIHNjb3JlLCBtaW5pbXVtIHNjb3JlLCBhbmQgc2FmZXR5IGluZGV4LiBBcyBoYXMgYmVlbiBwcmV2aW91c2x5IG5vdGVkLCBhdmVyYWdlIHNjb3JlcyBhcmUgcmVsYXRpdmVseSBoaWdoIGluIGVhY2ggemlwY29kZS4gTWludW11bSBzY29yZXMgY2FuIGJlIHF1aXRlIGxvdyAob25lIG9mIHRoZSBsb3dlc3Qgc2NvcmVzIGlzIDM2KSwgYnV0IHRoZXNlIGFyZSBmZXcgYW5kIGZhciBiZXR3ZWVuLgoKPGNlbnRlcj4hW1RhYmxlYXU6IEF2ZXJhZ2UgU2NvcmUgYnkgWWVhcl0oLi4vMDMgVmlzdWFsaXphdGlvbnMvQ3Jvc3N0YWJTY29yZXNieVllYXIucG5nKTwvY2VudGVyPgoKVGhpcyBjcm9zc3RhYiBpcyBhbHNvIGNvbG9yZWQgYnkgYSBTYWZldHkgSW5kZXguICBUaGlzIEtQSSBpcyBiYXNlZCBpbiBhIGNhbGN1bGF0ZWQgZmllbGQgdGhhdCBhY2NvdW50cyBmb3IgdGhlIGF2ZXJhZ2Ugc2NvcmUgYW5kIG1pbmltdW0gc2NvcmUgZm9yIGEgZ2l2ZW4gemlwIGNvZGUgaW4gYSBnaXZlbiB5ZWFyLCB0aGVuIHBhcmFtZXRlcml6ZWQgaW50byBMb3csIE1lZGl1bSwgYW5kIEhpZ2ggcmFua2luZ3MuICBUaGUgYnJlYWsgcG9pbnQgZm9yIGVhY2ggb2YgdGhlc2UgZ3JvdXBpbmdzIGNhbiBiZSBhZGp1c3RlZCB1c2luZyB0aGUgc2xpZGVycyB0byB0aGUgcmlnaHQgb2YgdGhlIGNyb3NzdGFiLiAgCgojIyMqKkJhcmNoYXJ0LXJlbGF0ZWQgVmlzdWFsaXphdGlvbnMgdXNpbmcgVGFibGVhdSoqCgoKIyMjIypDYXBNZXRybyBTdG9wcyBieSBaaXBjb2RlIGFzIHRoZXkgUmVsYXRlIHRvIFJlc3RhdXJhbnQgRGVuc2l0eSoKSGVyZSB3ZSBzZWUgdmlzdWFsaXplZCB0aGUgbnVtYmVyIG9mIGJ1cyBzdG9wcyBwZXIgemlwY29kZSwgY29sb3JlZCBieSB0aGUgbnVtYmVyIG9mIHJlc3RhdXJhbnRzIGluIHRoYXQgemlwY29kZS4gVGhpcyB2aXN1YWxpemF0aW9uIGFsc28gc2hvd3MgYW4gYXZlcmFnZSBsaW5lIGZvciB0aGUgYXZlcmFnZSBudW1iZXIgb2Ygc3RvcHMuIEFzIGlzIGV2aWRlbnQsIHRoZSB6aXBjb2RlcyB3aXRoIHRoZSBkYXJrZXN0IGJhcnMgKHRob3NlIHdpdGggdGhlIGhpZ2hlc3QgcmVzdHVhcmFudCBkZW5zaXR5KSwgYWxtb3N0IGFsd2F5cyBzdXJwYXNzIHRoZSBhdmVyYWdlIGxpbmUsIGJ1dCBhbHNvIGdlbmVyYWxseSBncmVhdGx5IHN1cnBhc3MgaXQuIFRoaXMgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSBpdCBzdWdnZXN0cyB0aGF0LCBpbiBnZW5lcmFsLCB6aXBjb2RlcyB3aXRoIGEgaGlnaGVyIHRoYW4gYXZlcmFnZSBudW1iZXIgb2YgYnVzIHN0b3BzIGFsc28gaGF2ZSBhIGhpZ2ggcmVzdHVhcmFudCBkZW5zaXR5LgoKPGNlbnRlcj4hW1RhYmxlYXU6IFN0b3BzIGJ5IFppcGNvZGVdKC4uLzAzIFZpc3VhbGl6YXRpb25zL1RCYXIxQS5wbmcpPC9jZW50ZXI+Cjxicj4KPGNlbnRlcj4hW1RhYmxlYXU6IFN0b3BzIGJ5IFppcGNvZGUsIEhpZ2ggUmVzdGF1cmFudCBEZW5zaXR5XSguLi8wMyBWaXN1YWxpemF0aW9ucy9UQmFyMUIucG5nKTwvY2VudGVyPgoKSW4gVGFibGVhdSwgdGhpcyB2aXN1YWxpemF0aW9uIGFsc28gYWxsb3dzIHlvdSB0byBhZGp1c3Qgd2hpY2ggemlwY29kZXMgYXJlIGRpc3BsYXllZCBiYXNlZCBvbiBhIG1pbmltdW0gYW1vdW50IG9mIHJlc3RhdXJhbnRzLCBhbmQgYWxzbyBiYXNlZCBvbiB3aGV0aGVyIHRoZSB6aXBjb2RlcyBhcmUgYWJvdmUgb3IgYmVsb3cgdGhpcyBtaW5pbXVtLgoKIyMjIypGb3JlaWduIFBvcHVsYXRpb24gdnMuIFJlc3RhdXJhbnQgRGVuc2l0eSoKSGVyZSB3ZSBmaW5kIGEgdmlzdWFsaXphdGlvbiB0aGF0IHNob3djYXNlcyBmb3JlaWduIHBvcHVsYXRpb24gYnkgemlwY29kZSwgYW5kIGlzIGNvbG9yZWQgdG8gcmVmbGVjdCB0aGUgcmVzdGF1cmFudCBkZW5zaXR5IG9mIGVhY2ggemlwY29kZS4gSW4gVGFibGVhdSwgeW91IGFyZSBhbHNvIGFibGUgdG8gdG9nZ2xlIGJhY2sgYW5kIGZvcnRoIGJldHdlZW4gYSBoaWdoZXIgdGhhbiBhdmVyYWdlLCBvciBhbiBhdC9iZWxvdyBhdmVyYWdlIGZvcmVpZ24gcG9wdWxhdGlvbi4KCjxjZW50ZXI+IVtUYWJsZWF1OiBSZXN0YXVyYW50IERlbnNpdHksIExvdyBGb3JlaWduIFBvcHVsYXRpb25dKC4uLzAzIFZpc3VhbGl6YXRpb25zL1RCYXIyQS5wbmcpPC9jZW50ZXI+Cjxicj4KPGNlbnRlcj4hW1RhYmxlYXU6IFJlc3RhdXJhbnQgRGVuc2l0eSwgSGlnaCBGb3JlaWduIFBvcHVsYXRpb25dKC4uLzAzIFZpc3VhbGl6YXRpb25zL1RCYXIyQi5wbmcpPC9jZW50ZXI+CgpGcm9tIHRoaXMgYmFyY2hhcnQsIGl0IHdvdWxkIHNlZW0gdGhhdCBoaWdoZXIgdGhhbiBhdmVyYWdlIGZvcmVpZ24gcG9wdWxhdGVkIHppcGNvZGVzIGRvbid0IG5lY2Vzc2FyaWx5IGhhdmUgYSBoaWdoZXIgcmVzdGF1cmFudCBkZW5zaXR5LiBPdmVyYWxsLCBpdCBhcHBlYXJzIHRoYXQgcmVzdGF1cmFudCBkZW5zaXR5IGlzIHByZXR0eSBldmVuIGFjcm9zcyBsZXZlbHMgb2YgZm9yZWlnbi1ib3JuIHBvcHVsYXRpb24gKGkuZS4gdGhlcmUgYXJlIHJlbGF0aXZlbHkgc2ltaWxhciBudW1iZXJzIG9mIGhpZ2ggcmVzdGF1cmFudCBkZW5zaXR5IHppcGNvZGVzIGluIGJvdGggY2F0ZWdvcmllcykuIFRoaXMgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSBpdCBzdWdnZXN0cyB0aGF0IHJlc3RhdXJhbnQgZGVuc2l0eSBtYXkgYmUgZmFpcmx5IGluZGVwZW5kZW50IG9mIGZvcmVpZ24tIG9yIG5hdGl2ZS1ib3JuIHBvcHVsYXRpb24gc3RhdHVzLgoKIyMjIypTdG9wIHRvIFJlc3R1YXJhbnQgUmF0aW9zIHBlciBaaXBjb2RlIGJ5IE5hdGl2aXR5KgpUaGlzIHZpc3VhbGl6YXRpb24gc2hvd3MgdGhlIHBvcHVsYXRpb25zIG9mIE5hdGl2ZSwgTmF0dXJhbGl6ZWQsIGFuZCBOb24tQ2l0aXR6ZW4gaW5oYWJpdGFudHMgZm9yIGVhY2ggemlwY29kZS4gRnVydGhlciwgdGhlc2UgYmFyY2hhcnRzIGFyZSBjb2xvcmVkIGJ5IHRoZSByZXN0YXVyYW50IHRvIHN0b3AgcmF0aW8gKGRhcmtlciBwdXJwbGUgaW5kaWNhdGVzIGEgaGlnaGVyIHJhdGlvKS4gVGhlIGhpZ2hlc3QgcmF0aW9zIGFyZSBiZXR3ZWVuIDc4NzIxIGFuZCA3ODcyNC4gCgo8Y2VudGVyPiFbVGFibGVhdTogU3RvcHMgdG8gUmVzdGF1cmFudHMgYnkgTmF0aXZpdHldKC4uLzAzIFZpc3VhbGl6YXRpb25zL1RCYXIzLnBuZyk8L2NlbnRlcj4KCkludGVyZXN0aW5nbHksIHRoZSBwb3B1bGF0aW9uIG9mIG5hdGl2ZSwgbmF0dXJhbGl6ZWQsIGFuZCBub24tY2l0aXplbiBwZW9wbGVzIGlzIHF1aXRlIHZhcmlhYmxlIGFjcm9zcyB6aXBjb2Rlcy4gQW5vdGhlciBpbnRlcmVzdGluZyBwb2ludCBpcyB0aGF0IGZvciBhbGwgdGhyZWUgY2F0ZWdvcmllcywgdGhlIGhpZ2hlc3QgcmF0aW9zIGFyZSBub3QgY29ycmVsYXRlZCB3aXRoIHRoZSBoaWdoZXN0IHBvcHVsYXRpb25zLiBUaGlzLCBvZiBjb3Vyc2UsIHNlZW1zIG5vbi1pbnR1aXRpdmUsIGFuZCBtYXkgYmUgYW4gYXJlYSBmb3IgZnV0dXJlIGlucXVpcnkuCgojIyoqVmlzdWFsaXphdGlvbnMgdXNpbmcgU2hpbnkgaW4gUioqClRoZSBzY3JlZW5zaG90cyBhbmQgZGVzY3JpcHRpb25zIGJlbG93IGFyZSBiYXNlZCBvbiBvdXIgaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiBhcHAsIGFjY2Vzc2libGUgYXQgaHR0cHM6Ly9rdmF1Z2huLnNoaW55YXBwcy5pby9yZXN0YXVyYW50X2luc3BlY3Rpb24vLgoKIyMjKipCb3hwbG90IFZpc3VhbGl6YXRpb24gdXNpbmcgU2hpbnkgaW4gUioqCk9uZSBsb3cgc2NvcmUgZG9lcyBub3QgaW5kaWNhdGUgYSBzeXN0ZW1pYyBwcm9ibGVtIHdpdGggYSByZXN0YXVyYW50J3MgY2xlYW5saW5lc3M7IGJlZm9yZSBqdWRnaW5nIGEgcmVzdGF1cmFudCB3aXRoIGEgbG93IHNjb3JlLCBpdCBiZWhvb3ZlcyB1cyB0byBjb25zaWRlciB0aGUgb3RoZXIgc2NvcmVzIGl0IGhhcyByZWNlaXZlZC4gIFRoaXMgYm94cGxvdCBhbGxvd3MgdGhlIHVzZXIgdG8gZG8ganVzdCB0aGF0LiAgRmlyc3Qgc2VsZWN0IGEgY3V0b29mIHBvaW50IGZvciBzY29yZXMsIHRoZW4gY2hvb3NlIGEgemlwY29kZSB0byBzZWUgYWxsIHJlc3RhdXJhbnRzIHRoYXQgaGF2ZSBzY29yZWQgYmVsb3cgdGhhdCBsZXZlbCBhdCBsZWFzdCBvbmUuICBFYWNoIHJlc3RhdXJhbnQncyBzY29yZXMgd2lsbCBkaXNwbGF5LCBnaXZpbmcgdGhlIHVzZXIgYW4gaWRlYSBvZiB3aGV0aGVyIHRoZSBsb3cgc2NvcmUgd2FzIGEgZmx1a2Ugb3IgYSBzaWduIG9mIHByb2JsZW1zLgoKPGNlbnRlcj4hW1NoaW55OiBTY29yZXMgYnkgUmVzdGF1cmFudCBEYXRhXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TQm94QS5wbmcpPC9jZW50ZXI+IAo8YnI+IAo8Y2VudGVyPiFbU2hpbnk6IFNjb3JlcyBieSBSZXN0YXVyYW50IEJveHBsb3RdKC4uLzAzIFZpc3VhbGl6YXRpb25zL1NCb3hCLnBuZyk8L2NlbnRlcj4KCiMjIyoqSGlzdG9ncmFtIFZpc3VhbGl6YXRpb24gdXNpbmcgU2hpbnkgaW4gUioqClRoaXMgdmlzdWFsaXphdGlvbiBhbGxvd3MgdGhlIHVzZXIgdG8gZ2V0IGEgYnJvYWRlciB2aWV3IG9mIHRoZSByZXN0YXVyYW50IGluc3BlY3Rpb24gc2NvcmVzLiAgVGhlIHVzZXIgaXMgZ2l2ZW4gdGhlIG9wdGlvbiB0byBzZWxlY3Qgc2NvcmVzIGZyb20gYW55IGNvbWJpbmF0aW9uIG9mIHllYXJzLiAgV2hhdCdzIGludGVyZXN0aW5nIGhlcmUgaXMgdGhhdCB0aGUgdmFzdCBtYWpvcml0eSBvZiByZXN0YXVyYW50IGluc3BlY3Rpb25zIHJlc3VsdCBpbiAicGFzc2luZyIgZ3JhZGVzIG9mIDcwIG9yIGhpZ2hlci4KCjxjZW50ZXI+IVtTaGlueTogQWxsIFNjb3JlcyBEYXRhXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TSGlzdEEucG5nKTwvY2VudGVyPiAKPGJyPgo8Y2VudGVyPiFbU2hpbnk6IEFsbCBTY29yZXMgSGlzdG9ncmFtXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TSGlzdEIucG5nKTwvY2VudGVyPgoKIyMjKipTY2F0dGVycGxvdCBWaXN1YWxpemF0aW9uIHVzaW5nIFNoaW55IGluIFIqKgpUaGUgU2NhdHRlcnBsb3QgdGFiIGluY2x1ZGVzIHRocmVlIHNlcGFyYXRlIHZpc3VhbGl6YXRpb25zIGRyYXduIGZyb20gb25lIHNldCBvZiBkYXRhLiAgVGhlIGZpcnN0IHZpc3VhbGl6YXRpb24gcGxvdHMgdGhlIHBvcHVsYXRpb24gb2YgYSB6aXBjb2RlIGFnYWluc3QgdGhlIG51bWJlciBvZiByZXN0YXVyYW50cyBpbiB0aGF0IHppcGNvZGUuICBUaGUgc2Vjb25kIGdyYXBoIHBsb3RzIHRoZSBwb3B1bGF0aW9uIHBlciB6aXBjb2RlIGFnYWluc3QgdGhlIHF1YW50aXR5IG9mIHRyYW5zaXQgc3RvcHMgaW4gdGhhdCB6aXBjb2RlLiAgKFRyYW5zaXQgc3RvcCBsb2NhdGlvbiBpbmZvcm1hdGlvbiBwcm92aWRlZCBieSBDYXBpdGFsIE1ldHJvIGFuZCBtYWRlIGF2YWlsYWJsZSB0aHJvdWdoIGRhdGEudGV4YXMuZ292OiBodHRwczovL2RhdGEudGV4YXMuZ292L2RhdGFzZXQvR1RGUy9yNHY0LXZ6MjQgKSAgQXMgeW91IHNlZSwgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHBvcHVsYXRpb24gYW5kIHJlc3RhdXJhbnQgb3IgdHJhbnNpdHktc3RvcCBxdWFudGl0eSBhcmUgcHJldHR5IHdlYWsuICBUaGUgdGhpcmQgdmlzdWFsaXphdGlvbiBpbiB0aGlzIHNldCBncmFwaHMgdHJhbnNpdCBzdG9wcyBieSByZXN0YXVyYW50cywgYW5kIHNob3dzIGEgbXVjaCBzdHJvbmdlciBjb3JyZWxhdGlvbi4gIFNlZSBhYm92ZSBmb3IgYSBkaXNjdXNzaW9uIG9mIG9uZSBwb3NzaWJsZSBleHBsYW5hdGlvbiBmb3IgdGhpcyBwYXR0ZXJuIG9mIHJlbGF0aW9uc2hpcHMuCgo8Y2VudGVyPiFbU2hpbnk6IFNjYXR0ZXJwbG90IERhdGFdKC4uLzAzIFZpc3VhbGl6YXRpb25zL1NTY2F0dGVyRGF0YS5wbmcpPC9jZW50ZXI+IAo8YnI+CjxjZW50ZXI+IVtTaGlueTogUmVzdGF1cmFudCBieSBQb3B1bGF0aW9uIFNjYXR0ZXJwbG90XSguLi8wMyBWaXN1YWxpemF0aW9ucy9TU2NhdHRlcjEucG5nKTwvY2VudGVyPgo8YnI+CjxjZW50ZXI+IVtTaGlueTogVHJhbnNpdCBieSBQb3B1bGF0aW9uIFNjYXR0ZXJwbG90XSguLi8wMyBWaXN1YWxpemF0aW9ucy9TU2NhdHRlcjIucG5nKTwvY2VudGVyPiAKPGJyPgo8Y2VudGVyPiFbU2hpbnk6IFJlc3RhdXJhbnQgYnkgVHJhbnNpdCBTY2F0dGVycGxvdF0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU1NjYXR0ZXIzLnBuZyk8L2NlbnRlcj4KCiMjIyoqQ3Jvc3N0YWIgVmlzdWFsaXphdGlvbnMgdXNpbmcgU2hpbnkgaW4gUioqCkNsaWNrIGhlcmUgdG8gYmUgdGFrZW4gdG8gb3VyIHB1Ymxpc2hlZCBTaGlueSBhcHA6IGh0dHBzOi8va3ZhdWdobi5zaGlueWFwcHMuaW8vcmVzdGF1cmFudF9pbnNwZWN0aW9uLwoKIyMjIypTYWZldHkgSW5kZXgqClRoaXMgdmlzdWFsaXphdGlvbiBzdGFydHMgd2l0aCBhIHNvbWV3aGF0LWFyYml0cmFyeSBLUEksIHRoZSAiU2FmZXR5IEluZGV4LCIgdGhhdCB0YWtlcyBpbnRvIGFjY291bnQgYm90aCB0aGUgYXZlcmFnZSBzY29yZSBhbmQgdGhlIGxvd2VzdCBpbnNwZWN0aW9uIHNjb3JlIHJlY2VpdmVkIGZvciBhIGdpdmVuIHppcCBjb2RlIGluIGEgZ2l2ZW4geWVhci4gIEEgaGlnaCBTYWZldHkgSW5kZXggaW5kaWNhdGVzIGJvdGggYSBoaWdoIGF2ZXJhZ2Ugc2NvcmUgYW5kIGEgaGlnaCBtaW5pbXVtIHNjb3JlLiAgU2V0IHRoZSBwYXJhbWV0ZXJzIGhvd2V2ZXIgeW91IGxpa2UgKDMgYW5kIDggYXJlIHJlYXNvbmFibGUgZGVmYXVsdHMpIGFuZCBjaGVjayB0aGUgY3Jvc3N0YWIgdG8gc2VlIGVhY2ggemlwIGNvZGUncyByYXRpbmdzIG92ZXIgdGhlIGZvdXIteWVhciBwZXJpb2QuCgo8Y2VudGVyPiFbU2hpbnk6IFNhZmV0eSBJbmRleCBEYXRhXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TQ3Jvc3MxQS5wbmcpPC9jZW50ZXI+IAo8YnI+CjxjZW50ZXI+IVtTaGlueTogU2FmZXR5IEluZGV4IENyb3NzdGFiXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TQ3Jvc3MxQi5wbmcpPC9jZW50ZXI+CgojIyMjKkxvd2VzdCBJbnNwZWN0aW9uIFNjb3JlcyoKVGhpcyB2aXN1YWxpemF0aW9uIGFsbG93cyB0aGUgdXNlciB0byBzZXQgYW4gYXJiaXRyYXJ5IGN1dG9mZiBwb2ludCBhcyBhbiBhaWQgZm9yIGlkZW50aWZ5aW5nIGxvdyBpbnNwZWN0aW9uIHNjb3Jlcy4gIFRoZSBkZWZhdWx0IHZhbHVlLCA3MCwgaXMgdGhlIGN1dG9mZiBmb3IgcmVzdGF1cmFudCBpbnNwZWN0aW9uczsgbG93ZXIgc2NvcmVzIHdpbGwgdHJpZ2dlciBhIHJlaW5zcGVjdGlvbi4gIEFmdGVyIHNlbGVjdGluZyBhIHBhcmFtZXRlciB1c2luZyB0aGUgc2xpZGVyIGFuZCByZXF1ZXN0aW5nIGRhdGEsIHRoZSB1c2VyIGNhbiBzZWxlY3QgdGhlICJDcm9zc3RhYiIgdGFiIHRvIHNlZSB3aGljaCB6aXAgY29kZXMgYW5kIHllYXJzIGhhZCB1bmFjY2VwdGFibHkgbG93IGluc3BlY3Rpb24gc2NvcmVzLgoKPGNlbnRlcj4hW1NoaW55OiBMb3dlc3QgSW5zcGVjdGlvbiBTY29yZXMgRGF0YV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0Nyb3NzMkEucG5nKTwvY2VudGVyPgo8YnI+CjxjZW50ZXI+IVtTaGlueTogTG93ZXN0IEluc3BlY3Rpb24gU2NvcmVzIENyb3NzdGFiXSguLi8wMyBWaXN1YWxpemF0aW9ucy9TQ3Jvc3MyQi5wbmcpPC9jZW50ZXI+CgojIyMjKlBlb3BsZSBwZXIgUmVzdGF1cmFudCoKQXVzdGluIGlzIGEgZmFzdC1ncm93aW5nIGNpdHksIGFuZCBvdXIgcmVzdGF1cmFudCBzY2VuZSBpcyBjdXJyZW50bHkgYm9vbWluZyBhcyB3ZWxsLiAgVGhpcyB2aXN1YWxpemF0aW9uIGFsbG93cyBhIHVzZXIgdG8gc2VlIHdoZXJlIHRoZSBkZW5zaXR5IG9mIHJlc3RhdXJhbnRzIGNvbXBhcmVkIHRvIHBvcHVsYXRpb24gaXMgaGlnaGVzdC4gIFVzaW5nIGEgcHVibGljIHBvcHVsYXRpb24gZGF0YXNldCBnZW5lcmF0ZWQgYnkgdGhlIFVTIENlbnN1cywgd2UgY2FuIGZpbmQgdGhlIG51bWJlciBvZiBwZW9wbGUgcGVyIHJlc3RhdXJhbnQgaW4gYSBnaXZlbiB6aXAgY29kZTsgYXMgbW9yZSByZXN0YXVyYW50cyBhcmUgYWRkZWQgKG9yIGZhaWwpLCB0aGUgcGVvcGxlLXBlci1yZXN0YXVyYW50IG51bWJlciBjaGFuZ2VzLiAgVGhlIGRlZmF1bHQgdmFsdWVzIGhpZ2hsaWdodCB0aGUgZGVuc2l0eSBvZiByZXN0YXVyYW50cyBpbiA3ODcwMSwgd2hpY2ggaXMgZG93bnRvd24gQXVzdGluLgoKPGNlbnRlcj4hW1NoaW55OiBQZW9wbGUgcGVyIFJlc3RhdXJhbnQgRGF0YV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0Nyb3NzM0EucG5nKTwvY2VudGVyPiAKPGJyPgo8Y2VudGVyPiFbU2hpbnk6IFBlb3BsZSBwZXIgUmVzdGF1cmFudCBDcm9zc3RhYl0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0Nyb3NzM0IucG5nKTwvY2VudGVyPgoKIyMjKipCYXJjaGFydCBWaXN1YWxpemF0aW9ucyB1c2luZyBTaGlueSBpbiBSKioKVGhlc2UgdmlzdWFsaXphdGlvbnMgYXJlIGFsc28gYWNjZXNzaWJsZSBhdCBodHRwczovL2t2YXVnaG4uc2hpbnlhcHBzLmlvL3Jlc3RhdXJhbnRfaW5zcGVjdGlvbi8KCiMjIyMqU2NvcmVzIGJ5IFppcCBDb2RlKgpCYXJjaGFydHMgY2FuIGJlIGEgZ29vZCB3YXkgdG8gcXVpY2tseSBpZGVudGlmeSB0cmVuZHMgdmlzdWFsbHkuICBJbiB0aGlzIHZpc3VhbGl6YXRpb24sIHRoZSB1c2VyIGNhbiBjcmVhdGUgYSBzZXQgb2YgemlwIGNvZGVzIG9mIGludGVyZXN0LCB0aGVuIHNlZSBlYWNoIHppcGNvZGUncyBhdmVyYWdlIHNjb3JlIHBlciB5ZWFyIG92ZXIgdGhlIHRocmVlIG9yIGZvdXIgeWVhcnMgY29udGFpbmVkIGluIHRoZSBkYXRhc2V0LgoKPGNlbnRlcj4hW1NoaW55OiBTY29yZXMgYnkgWmlwIENvZGUgRGF0YV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0JhcjFBLnBuZyk8L2NlbnRlcj4gCjxicj4KPGNlbnRlcj4hW1NoaW55OiBTY29yZXMgYnkgWmlwIENvZGUgQmFyIENoYXJ0XSguLi8wMyBWaXN1YWxpemF0aW9ucy9TQmFyMUIucG5nKTwvY2VudGVyPgoKIyMjIypUcmFuc2l0IHN0b3BzIGFuZCByZXN0YXVyYW50IGRlbnNpdHkqCkNhcGl0YWwgTWV0cm8sIHRoZSBBdXN0aW4tYXJlYSB0cmFuc2l0IHNlcnZpY2UsIGhhcyBtYWRlIGl0cyBkYXRhIGZyZWVseSBhdmFpbGFibGUgZm9yIHB1YmxpYyBkb3dubG9hZC4gIEJ5IGltcG9ydGluZyB0aGlzIGRhdGEgaW50byBnZW9ncmFwaGljIGluZm9ybWF0aW9uIHNvZnR3YXJlIChBcmNHSVMpIGFuZCBvdmVybGF5aW5nIHRoZSBjb29yZGluYXRlcyBvZiB0cmFuc2l0IHN0b3BzIG9uIGEgc2hhcGVmaWxlIG9mIHJlZ2lvbmFsIHppcCBjb2Rlcywgd2Ugd2VyZSBhYmxlIHRvIGNvdW50IHRoZSBudW1iZXIgb2YgdHJhbnNpdCBzdG9wcyBwZXIgemlwIGNvZGUuICBJbiB0aGlzIGJhciBjaGFydCwgd2UncmUgZXhhbWluaW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0cmFuc2l0IGRlbnNpdHkgYW5kIHJlc3RhdXJhbnQgZGVuc2l0eS4gIFVzZSB0aGUgc2xpZGVyIHRvIHNlbGVjdCB6aXAgY29kZXMgd2l0aCBtb3JlIHRoYW4gdGhlIG1pbmltdW0gbnVtYmVyIG9mIHRyYW5zaXQgc3RvcHMsIHRoZW4gY29tcGFyZSB0aGUgbnVtYmVyIG9mIHJlc3RhdXJhbnRzIGluIHRoZXNlIHppcCBjb2RlcyB0byB0aGUgYXZlcmFnZSBudW1iZXIgb2YgcmVzdGF1cmFudHMgcGVyIHppcCBjb2RlIHRocm91Z2hvdXQgdGhlIHJlZ2lvbi4gIFRoZSBibHVlIGxpbmUgaXMgdGhlIGNhbGN1bGF0ZWQgYXZlcmFnZSBmb3IgYWxsIG9mIHRoZSBzZWxlY3RlZCB6aXAgY29kZXMsIGFuZCB0aGUgcmVkIGlzIHRoZSBncmFuZCBhdmVyYWdlIGZvciBhbGwgb2YgdGhlIHppcGNvZGVzIGluIHRoZSBHcmVhdGVyIEF1c3RpbiBhcmVhLgoKPGNlbnRlcj4hW1NoaW55OiBSZXN0YXVyYW50IERlbnNpdHkgYW5kIFRyYW5zaXQgU3RvcHMgRGF0YV0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0JhcjJBLnBuZyk8L2NlbnRlcj4gCjxicj4KPGNlbnRlcj4hW1NoaW55OiBSZXN0YXVyYW50IERlbnNpdHkgYW5kIFRyYW5zaXQgU3RvcHMgQmFyIENoYXJ0XSguLi8wMyBWaXN1YWxpemF0aW9ucy9TQmFyMkIucG5nKTwvY2VudGVyPgoKIyMjIypOb25uYXRpdmUgcmVzaWRlbnRzIGFuZCByZXN0YXVyYW50IGRlbnNpdHkqCldvdWxkIHdlIGV4cGVjdCB6aXAgY29kZXMgd2l0aCBjb21wYXJhdGl2ZWx5IGxhcmdlIG51bWJlcnMgb2Ygbm9ubmF0aXZlIChuYXR1cmFsaXplZC1jaXRpemVuIG9yIG5vbmNpdGl6ZW4pIHJlc2lkZW50cyB0byBoYXZlIG1vcmUgb3IgZmV3ZXIgcmVzdGF1cmFudHMsIG9uIGF2ZXJhZ2UsIHRoYW4gemlwIGNvZGVzIHdpdGggbG93ZXIgcGVyY2VudGFnZXMgb2Ygbm9ubmF0aXZlIHJlc2lkZW50cz8gIFRoaXMgYmFyY2hhcnQgYWxsb3dzIHRoZSB1c2VyIHRvIHNlbGVjdCBhIG1pbmltdW0gcGVyY2VudGFnZSBvZiBub25uYXRpdmUgcmVzaWRlbnRzIHBlciB6aXAgY29kZSwgdGhlbiBzaG93cyB0aGUgbnVtYmVyIG9mIHJlc3RhdXJhbnRzIGluIHRoYXQgemlwIGNvZGUgYW5kIHRoZSBhdmVyYWdlIG51bWJlciBvZiByZXN0YXVyYW50cyBwZXIgemlwIGNvZGUgZm9yIGFsbCBvZiB0aGUgcXVhbGlmeWluZyB6aXAgY29kZXMuICBUaGlzIGF2ZXJhZ2UgY2FuIGJlIGNvbXBhcmVkIHRvIHRoZSBncmFuZCBhdmVyYWdlIHRocm91Z2hvdXQgdGhlIGdyZWF0ZXIgQXVzdGluIGFyZWEsIHNob3duIGluIHJlZC4KCjxjZW50ZXI+IVtTaGlueTogUmVzdGF1cmFudCBEZW5zaXR5IGFuZCBOb25uYXRpdmUgUmVzaWRlbnRzIERhdGFdKC4uLzAzIFZpc3VhbGl6YXRpb25zL1NCYXIzQS5wbmcpPC9jZW50ZXI+IAo8YnI+CjxjZW50ZXI+IVtTaGlueTogUmVzdGF1cmFudCBEZW5zaXR5IGFuZCBOb25uYXRpdmUgUmVzaWRlbnRzIEJhciBDaGFydF0oLi4vMDMgVmlzdWFsaXphdGlvbnMvU0JhcjNCLnBuZyk8L2NlbnRlcj4K